#written in python3
#Robert Hannan (emerson) April 17, 2020

#==================================================
#   REVISIONS
#==================================================

rev = 3.0

#   Rev3: fixed vector scanning code to prevent detecting false vector labels
#           replaced    if "NMI:" in line.upper()
#           with        if " NMI:" in line.upper()
#
#   Rev2: fixed byte encoding bug
#           replaced    vector_file.write(chr(int(nmi[2:4],16)))
#               with    vector_file.write(chr(int(nmi[2:4],16)).encode("raw_unicode_escape"))
#
#   Rev1: initial release



#==================================================
#   IMPORTS
#==================================================
import sys
import argparse



#==================================================
#   INITIALIZE VARIABLES
#==================================================
nmi = False
nmi1 = False
nmi2 = False
nmi3 = False
reset = False
irq = False
error = False



#==================================================
#   SUBROUTINES
#==================================================
#determine if vector label is commented out
#   and calculate address if label is valid
#   or return "False" if label is commented

def VectorAddressCalc(label):
    semicolon = line.find(";")
    label_position = line.find(label)
    x = line.find(" ")
    if semicolon == -1:
        address = line[x-4:x]
    else:
        if label_position < semicolon:
            address = line[x-4:x]
        else:
            address = False
    return (address)


#==================================================
#   MAIN PROGRAM
#==================================================
#Process entry arguments
parser = argparse.ArgumentParser()
parser.add_argument("infile", type=argparse.FileType("rt"), help="input '.lst' file containing vector labels")
parser.add_argument("outfile", type=argparse.FileType("w"), help="output '.bin' which contains vector addresses")
parser.add_argument("-q", "--quiet", action="store_true", default=False, help="display only warning and error messages")
parser.add_argument("-qe", "--quiet_error", action="store_true", default=False, help="disable all messages")
parser.add_argument("-r", "--revision", action="store_true", default=False, help="display current revision")
parser.parse_args()
args = parser.parse_args()



#check quiet modes and force quiet mode if error messages are disabled
q_mode = (args.quiet)
qe_mode = (args.quiet_error)
if qe_mode:
    q_mode = True


#print current revision
if not q_mode: print("FDS Vector Calculator Rev", rev)



#open source .lst file, scan for vector labels,
#   and assign results to relevant label variable
with open((args.infile.name), "rt") as source_file:
    for line in source_file:
        if " NMI:" in line.upper():
            nmi = VectorAddressCalc("NMI:")
        if " NMI1:" in line.upper():
            nmi1 = VectorAddressCalc("NMI1:")
        if " NMI2:" in line.upper():
            nmi2 = VectorAddressCalc("NMI2:")
        if " NMI3:" in line.upper():
            nmi3 = VectorAddressCalc("NMI3:")
        if " RESET:" in line.upper():
            reset = VectorAddressCalc("RESET:")
        if " IRQ:" in line.upper():
            irq = VectorAddressCalc("IRQ:")



#check to see if all vector labels have been assigned correctly
if nmi:
    if not q_mode: print("Vector label 'NMI' found")
else:
    if not qe_mode: print("Warning: No 'NMI' label found! Checking for 'NMI#' labels")    
    if nmi1:
        if not q_mode: print("Vector label 'NMI1' found")
    else:
        if not qe_mode: print("Error: No 'NMI1' label found!")
        error = True
    if nmi2:
        if not q_mode: print("Vector label 'NMI2' found")
    else:
        if not qe_mode: print("Error: No 'NMI2' label found!")
        error = True
    if nmi3:
        if not q_mode: print("Vector label 'NMI3' found")
    else:
        if not qe_mode: print("Error: No 'NMI3' label found!")
        error = True

if reset:
    if not q_mode: print("Vector label 'RESET' found")
else:
    if not qe_mode: print("Error: No 'RESET' label found!")
    error = True

if irq:
    if not q_mode: print("Vector label 'IRQ' found")
else:
    if not qe_mode: print("Error: No 'IRQ' label found!")
    error = True



#scan resulting variables and write vector addresses
#   to output_file
if error:
    if not qe_mode: print("Unable to complete '" + (args.outfile.name) + "'!") 
else:
    with open((args.outfile.name), "wb") as vector_file:
        if nmi:
            vector_file.write(chr(int(nmi[2:4],16)).encode("raw_unicode_escape"))    #nmi1
            vector_file.write(chr(int(nmi[0:2],16)).encode("raw_unicode_escape"))
            vector_file.write(chr(int(nmi[2:4],16)).encode("raw_unicode_escape"))    #nmi2
            vector_file.write(chr(int(nmi[0:2],16)).encode("raw_unicode_escape"))
            vector_file.write(chr(int(nmi[2:4],16)).encode("raw_unicode_escape"))    #nmi3
            vector_file.write(chr(int(nmi[0:2],16)).encode("raw_unicode_escape"))
        else:
            vector_file.write(chr(int(nmi1[2:4],16)).encode("raw_unicode_escape"))   #nmi1
            vector_file.write(chr(int(nmi1[0:2],16)).encode("raw_unicode_escape"))
            vector_file.write(chr(int(nmi2[2:4],16)).encode("raw_unicode_escape"))   #nmi2
            vector_file.write(chr(int(nmi2[0:2],16)).encode("raw_unicode_escape"))
            vector_file.write(chr(int(nmi3[2:4],16)).encode("raw_unicode_escape"))   #nmi3
            vector_file.write(chr(int(nmi3[0:2],16)).encode("raw_unicode_escape"))
        if reset:
            vector_file.write(chr(int(reset[2:4],16)).encode("raw_unicode_escape"))
            vector_file.write(chr(int(reset[0:2],16)).encode("raw_unicode_escape"))
        if irq:
            vector_file.write(chr(int(irq[2:4],16)).encode("raw_unicode_escape"))
            vector_file.write(chr(int(irq[0:2],16)).encode("raw_unicode_escape"))

    if not q_mode: print("Vector addresses written to '" + (args.outfile.name) + "'")

sys.exit(0)




    
